package com.google.code.gronono.commons.swing;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

import javax.swing.Icon;
import javax.swing.JOptionPane;
import javax.swing.JTree;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.metal.MetalLookAndFeel;

import org.apache.log4j.Logger;

/**
 * Classe contenant un ensemble d'utilitaire spécifique à Swing.
 *
 * @author Arnaud BRUNET
 */
public class SwingUtils {
	/** Logger. */
	private static final Logger logger = Logger.getLogger(SwingUtils.class);

	/**
	 * La classe est une classe utilitaire.
	 * Son constructeur ne doit jamais être appelé.
	 * @throws UnsupportedOperationException Toujours.
	 */
	private SwingUtils() {
		throw new UnsupportedOperationException();
	}

	/**
	 * Pack (au sens {@link Window#pack()} la fenêtre spécifiée
	 * et ajoute un listener empêchant la fenêtre d'être redimensionnée en dessous de sa taille minimale.
	 *
	 * @param window La fenêtre.
	 *
	 * @see Window#pack()
	 */
	public static void pack(final Window window) {
		window.pack();
		final Dimension minDimension = window.getSize();
		window.setMinimumSize(minDimension);
		window.addComponentListener(new ComponentAdapter() {
			@Override
			public void componentResized(final ComponentEvent e) {
				final Component cp = e.getComponent();
				if (cp.getSize().width < cp.getMinimumSize().width) {
					cp.setSize(cp.getMinimumSize().width, cp.getSize().height);
				}
				if (cp.getSize().height < cp.getMinimumSize().height) {
					cp.setSize(cp.getSize().width, cp.getMinimumSize().height);
				}
			}
		});
	}

	/**
	 * Change le {@link LookAndFeel} de l'application en fonction de la plate-forme sur laquelle est lancé le programme.
	 */
	public static void setSystemLookAndFeel() {
		String lookAndFeelClassName = UIManager.getSystemLookAndFeelClassName();
		if (lookAndFeelClassName.equals(MetalLookAndFeel.class.getName()) || lookAndFeelClassName.equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel")) {
			// Si le thème par défaut est Motif ou GTK, on force à métal
			lookAndFeelClassName = MetalLookAndFeel.class.getName();
		}
		if (lookAndFeelClassName.equals(MetalLookAndFeel.class.getName())) {
			MetalLookAndFeel.setCurrentTheme(new DefaultOceanTheme());
		}
		try {
			logger.debug("Look And Feel Class : " + lookAndFeelClassName);
			UIManager.setLookAndFeel(lookAndFeelClassName);
		} catch (final ClassNotFoundException e) {
			// Ne peut pas se produire
			logger.error(e);
		} catch (final InstantiationException e) {
			// Ne peut pas se produire
			logger.error(e);
		} catch (final IllegalAccessException e) {
			// Ne peut pas se produire
			logger.error(e);
		} catch (final UnsupportedLookAndFeelException e) {
			// Ne peut pas se produire
			logger.error(e);
		}
	}

	/**
	 * Permet de récupérer l'icône associée au type de message spécifiée. <br/>
	 * Utilise en interne les icônes de {@link JOptionPane} dépendant du système sur lequel le programme est lancé. <br/>
	 *
	 * @param messageType Le type du message.
	 *
	 * @return L'icône associée au type de message.
	 */
	public static Icon getIconForType(final MessageType messageType) {
		switch (messageType) {
		case QUESTION:
			return UIManager.getIcon("OptionPane.questionIcon");
		case INFORMATION:
			return UIManager.getIcon("OptionPane.informationIcon");
		case WARNING:
			return UIManager.getIcon("OptionPane.warningIcon");
		case ERROR:
			return UIManager.getIcon("OptionPane.errorIcon");
		default:
			throw new IllegalStateException("Unsupported messageType : " + messageType);
		}
	}

	/**
	 * Permet de développer totalement l'arbre spécifié.
	 *
	 * @param tree L'arbre à développer.
	 */
	public static void expandAll(final JTree tree) {
		for (int row = 0; row < tree.getRowCount(); row++) {
			tree.expandRow(row);
		}
    }

	/**
	 * Permet de réduire totalement l'arbre spécifié.
	 *
	 * @param tree L'arbre à réduire.
	 */
	public static void collapseAll(final JTree tree) {
		for (int row = 0; row < tree.getRowCount(); row++) {
			tree.collapseRow(row);
		}
    }

}
